package com.haidechizi.i18n.code.generator.common.message.generator;


import com.haidechizi.i18n.code.generator.common.message.config.GeneratorProperties;
import com.haidechizi.i18n.code.generator.common.message.global.GlobalParam;
import com.haidechizi.i18n.code.generator.common.message.holder.GeneratorHolder;
import com.haidechizi.i18n.code.generator.common.message.key.KeyGeneratorAdapter;
import com.haidechizi.i18n.code.generator.common.message.language.Language;
import com.haidechizi.i18n.code.generator.common.message.language.LanguageHelper;
import com.haidechizi.i18n.code.generator.common.message.reader.Reader;
import com.haidechizi.i18n.code.generator.common.message.utils.FileTypeUtils;
import com.haidechizi.i18n.code.generator.common.message.utils.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;

import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.LongAdder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public abstract class BaseCodeGenerator implements CodeGenerator {

    @Autowired
    protected KeyGeneratorAdapter keyGeneratorAdapter;

    @Autowired
    private Reader reader;

    /**
     * 存储key,语言，value
     * <p>
     * {
     * tip.value :{
     * zh_cn : "消息",
     * en_US : "message"
     * }
     * }
     */
    protected ThreadLocal<Map<String, Map<String, String>>> languageMessageMap = new ThreadLocal() {

        @Override
        protected Object initialValue() {
            return new HashMap<String, String>();
        }
    };


    /**
     * 存储中文和对应key的关系
     * {
     * "中文"：key
     * }
     */
    protected ThreadLocal<Map<String, String>> messageMap = new ThreadLocal() {

        @Override
        protected Object initialValue() {
            return new HashMap<String, String>();
        }
    };


    /**
     * 存储中文和对应key的关系
     * {
     * "randomKey"：注释
     * }
     */
    protected ThreadLocal<Map<String, String>> noteStrMap = new ThreadLocal() {

        @Override
        protected Object initialValue() {
            return new HashMap<String, String>();
        }
    };

    protected LongAdder longAdder = new LongAdder();

    private static final String suffix = ".bak";

    @Autowired
    private GeneratorProperties configuration;

    /**
     * 初始化所有代码生成器
     */
    @PostConstruct
    public void init() {
        GeneratorHolder.addGenerator(this.type(), this);
    }

    /**
     * 生成代码
     *
     * @param path
     */
    @Override
    public void generator(String path) {
        // 判断是否支持当前后缀
        String fileSuffix = FileTypeUtils.fileSuffix(path);
        if (!isSupport(fileSuffix)) {
            return;
        }

        // 获取对应的语言生成类
        List<Language> languageList = LanguageHelper.getLanguageList(GlobalParam.getParam().getLanguageTypeList());

        // 文件中是否包含中文
        boolean hasChinese = false;

        // 读取文件的内容
        String content = reader.readFile(path);

        // 通用处理，匹配注释中的中文
        content = dealNoteString(content);

        // 前置处理器
        content = beforeTranslate(path, content);
        // 通过正则匹配替换文件中的内容
        for (String regex : GeneratorHelper.getRegexList()) {

            // 验证文件是否有内容匹配
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(content);
            // 判断文件中是否有中文
            while (matcher.find()) {
                // 正则匹配出来的中文
                String cnData = matcher.group(1);
                String key = generateKey(cnData, fileSuffix, content);

                // 替换文件中的标点符号
                key = key.replaceAll("[!\\_]\\pP", "");
                // 添加中文key的对应关系
                putMessageMapping(cnData, key);

                // 生成对应的语言
                LanguageHelper.generateLanguage(languageList, key, cnData, languageMessageMap.get());
                // 替换对应的语言
                content = content.replace(generateResourceData(cnData, content, matcher, fileSuffix), generateReplaceData(key, cnData, content, fileSuffix));

                // 匹配到了中文
                hasChinese = true;
                matcher = pattern.matcher(content);
            }
        }

        // 将注释中的中文字符串还原
        content = recoverNoteString(content);
        // 后置处理器
        content = afterTranslate(content, path);
        // 文件中是否包含中文
        if (hasChinese) {
            // 是否生成备份文件
            if (GlobalParam.getParam().isBackupFile()) {
                FileUtils.copyFile(path, suffix);
            }

            // 生成新的文件
            if (GlobalParam.getParam().isGenerateNewFile()) {
                FileUtils.createFile(content, path, ".new");
            }

            // 是否替换原
            if (GlobalParam.getParam().isReplaceFile()) {
                FileUtils.createFile(content, path, "");
            }
        }
    }

    /**
     * 释放本次翻译的ThreadLocal资源
     */
    @Override
    public void releaseResources() {
        languageMessageMap.remove();
        messageMap.remove();
        noteStrMap.remove();
    }

    /**
     * 前置处理器
     *
     * @param path
     * @param content
     * @return
     */
    protected String beforeTranslate(String path, String content) {
        return content;
    }

    /**
     * 后置处理器
     *
     * @param content
     * @param path
     * @return
     */
    protected String afterTranslate(String content, String path) {
        return content;
    }

    /**
     * 生成properties资源key
     *
     * @param cnData
     * @param fileSuffix
     * @param content
     * @return
     */
    protected abstract String generateKey(String cnData, String fileSuffix, String content);

    /**
     * 生成需要替换的资源
     *
     * @param cnData
     * @param content
     * @param matcher
     * @return
     */
    protected String generateResourceData(String cnData, String content, Matcher matcher, String fileSuffix) {
        // 获取引号+中文 "中文"
        return matcher.group();
    }

    protected String generateReplaceData(String key, String cnData, String content, String fileSuffix) {
        return "I18nStaticInfoUtil.translate(\"" + key + "\")";
    }

    private void putMessageMapping(String cnData, String key) {
        messageMap.get().put(cnData, key);
    }

    private String dealNoteString(String content) {
        String suffix = "!@note";
        String prefix = "@!";
        for (String regex : configuration.getNoteRegexList()) {

            // 验证文件是否有内容匹配
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(content);
            // 判断文件中是否有中文
            while (matcher.find()) {
                // 正则匹配出来的中文
                String group = matcher.group();

                String key = prefix + getAndAdd() + suffix;

                noteStrMap.get().put(key, group);

                content = content.replace(group, key);

                matcher = pattern.matcher(content);

            }
        }
        return content;
    }

    private String recoverNoteString(String content) {
        Map<String, String> stringMap = noteStrMap.get();
        for (Map.Entry<String, String> entry : stringMap.entrySet()) {
            content = content.replace(entry.getKey(), entry.getValue());
        }
        // 清空字符
        noteStrMap.get().clear();
        return content;
    }

    protected long getAndAdd() {
        longAdder.increment();
        return longAdder.longValue();
    }


}
